//
//  notMac.m
//  notMac
//
//  Created by Iain Wade on 7/01/07.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "notMac.h"

#define NOTMAC_UA @"notMac/0.1"
#define SERVICEURL_PREF @"net.notmac.serviceURL"
#define USERNAME_PREF @"net.notmac.username"
#define KEYCHAIN_SERVICE @"notMac"

@implementation notMac

+ (void)clearEnvironment
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *user = [defaults stringForKey:USERNAME_PREF];

    [defaults removeObjectForKey:SERVICEURL_PREF];
    [defaults removeObjectForKey:USERNAME_PREF];

    if (user && [user length])
    {
	KeychainItem *item;
		
	while (item = [[Keychain defaultKeychain] genericService:KEYCHAIN_SERVICE forAccount:user])
            [item deleteCompletely];
    }

    NSString *resourcePath = [[NSBundle bundleForClass:[self class]] resourcePath];
    NSString *helper = [resourcePath stringByAppendingPathComponent:@"syncHelper"];
    [[NSTask launchedTaskWithLaunchPath:helper arguments:[NSArray arrayWithObject:@"--unregister"]] waitUntilExit];
}

+ (id)notMacFromEnvironment
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *URL = [defaults objectForKey:SERVICEURL_PREF inDomain:@"com.apple.systempreferences"];
    NSString *user = [defaults objectForKey:USERNAME_PREF inDomain:@"com.apple.systempreferences"];
    NSString *pass = nil;

    if (URL && [URL hasPrefix:@"http"] && user && [user length])
    {
        pass = [[Keychain defaultKeychain] passwordForGenericService:KEYCHAIN_SERVICE forAccount:user];
		
	if (pass && [pass length])
	    return [[[[self class] alloc] initWithUsername:user password:pass serviceURL:URL] autorelease];
    }
	
    return nil;
}

+ (id)notMacWithUsername:(NSString *)user password:(NSString *)pass serviceURL:(NSString *)URL
{
    return [[[[self class] alloc] initWithUsername:user password:pass serviceURL:URL] autorelease];
}

- (id)initWithUsername:(NSString *)user password:(NSString *)pass serviceURL:(NSString *)URL
{
    if (self = [super init])
    {
        username = [user retain];
	password = [pass retain];
	serviceURL = [URL retain];
    }
	
    return self;
}

- (NSObject *)rpcAction:(NSString *)action withObject:(id)object
{
    NSURL *rpcUrl = [NSURL URLWithString:serviceURL];

    NSLog(@"sending %@ with %@", action, object);

    XMLRPCRequest *request = [[XMLRPCRequest alloc] initWithHost:rpcUrl];
    [request setUserAgent:NOTMAC_UA];
    [request setMethod:action withObject:object];

    XMLRPCResponse *response = [XMLRPCConnection sendSynchronousXMLRPCRequest:request];

    [request release];

    if (!response || [response isFault])
	return nil;

    return [response object];
}

- (BOOL)validate
{
    if ([self rpcAction:@"validateAccount" withObject:[NSDictionary dictionaryWithObjectsAndKeys:
	username, @"username",
	password, @"password",
	nil]])
    {
	return YES;
    }

    return NO;
}

- (void)saveToEnvironment
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:username forKey:USERNAME_PREF];
    [defaults setObject:serviceURL forKey:SERVICEURL_PREF];

    NSString *resourcePath = [[NSBundle bundleForClass:[self class]] resourcePath];
    NSString *helper = [resourcePath stringByAppendingPathComponent:@"syncHelper"];

    NSArray *apps = [NSArray arrayWithObjects:
        [TrustedApplication trustedApplicationWithPath:nil],
        [TrustedApplication trustedApplicationWithPath:helper],
        nil];

    KeychainItem *item = [[Keychain defaultKeychain]
        addNewItemWithClass:kSecGenericPasswordItemClass
        access:[Access accessWithName:KEYCHAIN_SERVICE applications:apps]];

    [item setLabel:KEYCHAIN_SERVICE];
    [item setService:KEYCHAIN_SERVICE];
    [item setAccount:username];
    [item setDataString:password];

    [[NSTask launchedTaskWithLaunchPath:helper arguments:[NSArray arrayWithObject:@"--register"]] waitUntilExit];
}

- (NSDictionary *)storageInfo
{
    return (NSDictionary *)[self rpcAction:@"queryStorageInfo" withObject:[NSDictionary dictionaryWithObjectsAndKeys:
	username, @"username",
	password, @"password",
	nil]];
}

- (NSString *)username
{
    return username;
}

- (NSString *)password
{
    return password;
}

- (NSString *)serviceURL
{
    return serviceURL;
}

- (NSString *)openSession:(NSString *)clientIdentifier
{
    NSDictionary *dict = (NSDictionary *)[self rpcAction:@"openSession" withObject:[NSDictionary dictionaryWithObjectsAndKeys:
	username, @"username",
	password, @"password",
	clientIdentifier, @"clientIdentifier",
	nil]];
		
    if (dict && (sid = [dict valueForKey:@"sid"]) && (run = [dict valueForKey:@"run"]))
	return run;
	
    return nil;
}

- (NSDictionary *)getRecordsOfType:(NSString *)entityName sinceRun:(NSString *)sinceRun
{
    if (!sid)
	return NO;

    NSDictionary *dict = (NSDictionary *)[self rpcAction:@"getRecords" withObject:[NSDictionary dictionaryWithObjectsAndKeys:
	sid, @"sid",
	entityName, @"entityName",
	sinceRun, @"sinceRun",
	nil]];

    if (dict && [dict objectForKey:@"deleted"] && [dict objectForKey:@"records"])
	return dict;

    return nil;
}

- (BOOL)deleteAllRecordsOfType:(NSString *)entityName
{
    if (!sid)
	return NO;
		
    if ([self rpcAction:@"deleteAllRecords" withObject:[NSDictionary dictionaryWithObjectsAndKeys:
	sid, @"sid",
	entityName, @"entityName",
	nil]])
    {
	return YES;
    }
	
    return NO;
}

- (BOOL)deleteRecordWithIdentifier:(NSString *)identifier ofType:(NSString *)entityName
{
    if (!sid)
	return NO;
	
    if ([self rpcAction:@"deleteRecord" withObject:[NSDictionary dictionaryWithObjectsAndKeys:
	sid, @"sid",
	entityName, @"entityName",
	identifier, @"recordIdentifier",
	nil]])
    {
	return YES;
    }
	
    return NO;
}

- (BOOL)replaceRecord:(NSData *)record withIdentifier:(NSString *)identifier ofType:(NSString *)entityName
{
    if (!sid)
	return NO;
		
    if ([self rpcAction:@"replaceRecord" withObject:[NSDictionary dictionaryWithObjectsAndKeys:
	sid, @"sid",
	entityName, @"entityName",
	identifier, @"recordIdentifier",
	record, @"record",
	nil]])
    {
	return YES;
    }
	
    return NO;
}

- (BOOL)finishSession
{
    if (!sid)
	return YES;
		
    if ([self rpcAction:@"closeSession" withObject:[NSDictionary dictionaryWithObjectsAndKeys:
	sid, @"sid",
	nil]])
    {
	sid = nil;
	run = nil;

	return YES;
    }
	
    return NO;
}

- (void)dealloc
{
    if (sid)
	[self finishSession];

    [super dealloc];
}

@end
